package net.oschina.victor.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.shiro.authz.permission.WildcardPermission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import net.oschina.victor.entity.Resource;
import net.oschina.victor.repsotory.ResourceRepsotory;

@Service
public class ResourceServiceImpl implements ResourceService {
	@Autowired
	private ResourceRepsotory resourceRepsotory;

	@Override
	public Resource saveResource(Resource resource) {
		return resourceRepsotory.save(resource);
	}

	@Override
	public void deleteResource(Long resourceId) {
		resourceRepsotory.delete(resourceId);
	}

	@Override
	public Resource findById(Long resourceId) {
		return resourceRepsotory.findOne(resourceId);
	}

	@Override
	public List<Resource> findAll() {
		Specification<Resource> spec = new Specification<Resource>() {
			@Override
			public Predicate toPredicate(Root<Resource> arg0, CriteriaQuery<?> arg1, CriteriaBuilder arg2) {
				return null;
			}
		};
		return resourceRepsotory.findAll(spec);
	}

	@Override
	public Set<String> findPermissions(Set<Resource> resources) {
		Set<String> permissions = new HashSet<String>();
		for (Resource resource : resources) {
			if (resource != null && !StringUtils.isEmpty(resource.getPermission())) {
				permissions.add(resource.getPermission());
			}
		}
		return permissions;
	}

	@Override
	public List<Resource> findMenus(Set<String> permissions) {
		List<Resource> allResources = findAll();
		List<Resource> menus = new ArrayList<Resource>();
		for (Resource resource : allResources) {
			if (resource.isRootNode()) {
				continue;
			}
			if (resource.getType() != Resource.ResourceType.MENU) {
				continue;
			}
			if (!hasPermission(permissions, resource)) {
				continue;
			}
			menus.add(resource);
		}
		return menus;
	}

	private boolean hasPermission(Set<String> permissions, Resource resource) {
		if (StringUtils.isEmpty(resource.getPermission())) {
			return true;
		}
		for (String permission : permissions) {
			WildcardPermission p1 = new WildcardPermission(permission);
			WildcardPermission p2 = new WildcardPermission(resource.getPermission());
			if (p1.implies(p2) || p2.implies(p1)) {
				return true;
			}
		}
		return false;
	}
}
